package com.wao.editor.web.rest;

import com.codahale.metrics.annotation.Timed;
import com.wao.editor.domain.BaseState;
import com.wao.editor.domain.FileListing;
import com.wao.editor.domain.State;
import com.wao.editor.service.FileManager;
import com.wao.editor.util.JsonUtils;
import com.wao.editor.web.rest.errors.UploadErrorVM;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * REST controller for managing File.
 */
@RestController
@RequestMapping("/api/kindeditor")
public class KindEditorResource {

    private final Logger log = LoggerFactory.getLogger(KindEditorResource.class);

    //定义允许上传的文件扩展名
    private static HashMap<String, String> extMap = new HashMap<String, String>();

    //最大文件大小
    private static long maxSize = 10000000;

    //路径前缀
    private static String prefix = "kindeditor/image/";

    private static String domain;

    //图片扩展名
    String[] fileTypes = new String[]{"gif", "jpg", "jpeg", "png", "bmp"};

    private final FileManager fileManager;

    public KindEditorResource(FileManager fileManager) {
        this.fileManager = fileManager;
    }

    @PostConstruct
    public void afterPropertiesSet() {
        extMap.put("image", "gif,jpg,jpeg,png,bmp");
//        extMap.put("flash", "swf,flv");
//        extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
//        extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");
        String domainStr = fileManager.getDomains().stream().filter(e -> StringUtils.isNotBlank(e)).findAny().orElse("");
        this.domain = StringUtils.isBlank(domainStr) ? "" : ("http://" + domainStr + "/");

    }

    /**
     * POST  /images : upload a image .
     *
     * @param dirName the dir name
     * @return the ResponseEntity with status 200 (upload success)
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PostMapping("/images")
    @Timed
    public ResponseEntity<String> uploadImages(@RequestParam(name = "dir", required = false) String dirName,
                                               MultipartHttpServletRequest request) {
        log.debug("REST request to upload a {} file ", dirName);
        UploadErrorVM resp;
        if (dirName == null)
            dirName = "image";
        String referer = request.getHeader("referer");
        Pattern p = Pattern.compile("([a-z]*:(//[^/?#]+)?)?", Pattern.CASE_INSENSITIVE);
        Matcher mathcer = p.matcher(referer);
        String callBackPath = "";
        if (mathcer.find())
            callBackPath = mathcer.group();
        if (!ServletFileUpload.isMultipartContent(request)) {
            resp = new UploadErrorVM("请选择文件。");
        } else if (!extMap.containsKey(dirName)) {
            resp = new UploadErrorVM("目录名不正确。");
        } else {
            MultipartFile file = ((MultipartHttpServletRequest) request).getFile("imgFile");
            String fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
            //检查文件大小
            if (file.getSize() > maxSize) {
                resp = new UploadErrorVM("上传文件大小超过限制。");
            }
            //检查扩展名
            else if (!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)) {
                resp = new UploadErrorVM("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。");
            } else {
                try {
                    State storageState = fileManager.saveFileByInputStream(file.getInputStream(), file.getOriginalFilename(), maxSize, prefix);
                    if (storageState.isSuccess()) {
                        resp = new UploadErrorVM(0, domain + ((BaseState) storageState).getString("url"), null);
                    } else {
                        resp = new UploadErrorVM("上传文件失败。");
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                    resp = new UploadErrorVM("上传文件失败。");
                }
            }
        }
        String respStr = JsonUtils.toJson(resp);
        StringBuilder sb = new StringBuilder("<iframe id=\"frame1\" src='");
        sb
                .append(callBackPath)
                .append("/#/u?params=")
                .append(respStr)
                .append("' frameborder=\"0\"></iframe>");
        log.debug(String.format("upload success url:%s", sb.toString()));
        return ResponseEntity.ok(sb.toString());
    }

    /**
     * GET  /files : get all files .
     *
     * @param dirName the dir name
     * @return the ResponseEntity with status 200 (OK) and with body the FileListing,
     * or with status 500 (Internal server error) if failed to get the file list.
     */
    @GetMapping("/images")
    @Timed
    public ResponseEntity<?> getImageList(@RequestParam(name = "dir", required = false) String dirName,
                                          @RequestParam(name = "order", required = false) String order) {
        log.debug("REST request to get a list of files");
        //遍历目录取的文件信息
        List<Hashtable> fileList = new ArrayList<Hashtable>();
        boolean isEOF = false;
        String marker = null;
        while (!isEOF) {
            FileListing listing = fileManager.listFiles(prefix, marker, 1000);
            listing.getItems().forEach(file -> {
                Hashtable<String, Object> hash = new Hashtable<String, Object>();
                String fileName = file.getKey();
                fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
                String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                hash.put("is_dir", false);
                hash.put("has_file", false);
                hash.put("filesize", file.getFsize());
                hash.put("is_photo", Arrays.<String>asList(fileTypes).contains(fileExt));
                hash.put("filetype", fileExt);
                hash.put("filename", fileName);
                hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.getPutTime() / 10000)));
                fileList.add(hash);
            });
            marker = listing.getMarker();
            isEOF = listing.isEOF();
        }
        if ("size".equals(order)) {
            Collections.sort(fileList, new SizeComparator());
        } else if ("type".equals(order)) {
            Collections.sort(fileList, new TypeComparator());
        } else {
            Collections.sort(fileList, new NameComparator());
        }
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("moveup_dir_path", "");
        result.put("current_dir_path", "");
        result.put("current_url", domain + prefix);
        result.put("total_count", fileList.size());
        result.put("file_list", fileList);
        return ResponseEntity.ok(result);
    }

    public class NameComparator implements Comparator {
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                return ((String) hashA.get("filename")).compareTo((String) hashB.get("filename"));
            }
        }
    }

    public class SizeComparator implements Comparator {
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                if (((Long) hashA.get("filesize")) > ((Long) hashB.get("filesize"))) {
                    return 1;
                } else if (((Long) hashA.get("filesize")) < ((Long) hashB.get("filesize"))) {
                    return -1;
                } else {
                    return 0;
                }
            }
        }
    }

    public class TypeComparator implements Comparator {
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                return ((String) hashA.get("filetype")).compareTo((String) hashB.get("filetype"));
            }
        }
    }
}
